//
//  HQQNetworkManager.m
//  HQQNetworkExemple
//
//  Created by 黄强强 on 16/7/7.
//  Copyright © 2016年 黄强强. All rights reserved.
//

#import "HQQNetworkManager.h"
#import <AFNetworking.h>
#import "UIDevice+HQQNetwork.h"
#import <HQQiOSCache+TMCache.h>
#import <MJExtension.h>

NSInteger const HQQNetworkStatusOK = 1;
NSInteger const HQQNetworkStatusFail = 0;

static HQQNetworkManager *_instance = nil;
@implementation HQQNetworkManager

#pragma mark - init

+ (instancetype)sharedManager
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}

#pragma mark - GET

- (void)GET:(NSString *)urlString paramters:(NSDictionary *)paramters responseClass:(__unsafe_unretained Class)responseClass success:(HQQNetworkSuccessBlock)success failure:(HQQNetworkFailureBlock)failure
{
    [self GET:urlString paramters:paramters needCache:NO responseClass:responseClass success:success failure:failure];
}

- (void)GET:(NSString *)urlString paramters:(NSDictionary *)paramters needCache:(BOOL)needCache responseClass:(Class)responseClass success:(HQQNetworkSuccessBlock)success failure:(HQQNetworkFailureBlock)failure
{
    // 1. 验证token
    
    // 2. 处理url，添加公共参数
    NSString *resultURL = [self setCommonParamtersWithURL:urlString];
    
    // 3. 是否有缓存，如果有从缓存中取，返回success
    if (needCache && resultURL && success) {
        // 3.1 根据url查看缓存
        id cacheObject = [HQQiOSCache objectForKey:urlString];
        
        if (responseClass) {
            if ([cacheObject isKindOfClass:responseClass]) {
                success(HQQNetworkStatusOK, nil,cacheObject);
            }
            else if ([cacheObject isKindOfClass:[NSArray class]]) {
                NSArray *arr = (NSArray *)cacheObject;
                if (arr && arr.count > 0) {
                    id obj = [arr firstObject];
                    if ([obj isKindOfClass:responseClass]) {
                        success(HQQNetworkStatusOK, nil, cacheObject);
                    }
                }
            }
        }
        else{
            success(HQQNetworkStatusOK, nil, cacheObject);
        }
    }
    
    // 4. 添加请求头
    AFHTTPSessionManager *manager = [self createSessionManager];
    
    // 5. 发送请求
    [manager GET:urlString parameters:paramters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        NSInteger status = HQQNetworkStatusFail;
        NSString *message = nil;
        id response = nil;
        
        // test: 转化model
        NSString *error = responseObject[@"error"];
        if (error.integerValue == 0) {
            status = HQQNetworkStatusOK;
        }else{
            status = HQQNetworkStatusFail;
        }
        message = responseObject[@"message"];
        response = responseObject[@"result"];
        if ([response isKindOfClass:[NSArray class]]) {
            NSArray *responseArr = (NSArray *)responseObject;
            NSMutableArray *resultArr = [NSMutableArray array];
            for (id model in responseArr) {
                id object = [responseClass mj_objectWithKeyValues:model];
                [resultArr addObject:object];
            }
            response = resultArr;
        }
        else{
            if (responseClass) {
                response = [responseClass mj_objectWithKeyValues:responseObject];
            }
        }
        
        // 6. 是否缓存
        if (needCache) {
            // 6.1 缓存json
            [HQQiOSCache setObject:response forKey:urlString];
        }
        
        // 7. 回调
        if (success) {
            success(status,message,response);
        }
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        if (failure) {
            failure(error);
        }
    }];
}

#pragma mark - POST

- (void)POST:(NSString *)urlString paramters:(NSDictionary *)paramters responseClass:(__unsafe_unretained Class)responseClass success:(HQQNetworkSuccessBlock)success failure:(HQQNetworkFailureBlock)failure
{
    [self POST:urlString paramters:paramters needCache:NO responseClass:responseClass success:success failure:failure];
}

- (void)POST:(NSString *)urlString paramters:(NSDictionary *)paramters needCache:(BOOL)needCache responseClass:(__unsafe_unretained Class)responseClass success:(HQQNetworkSuccessBlock)success failure:(HQQNetworkFailureBlock)failure
{
    
}

#pragma mark - 设置url公共参数

- (NSString *)setCommonParamtersWithURL:(NSString *)urlString
{
    return urlString;
}

#pragma mark - 创建AFHTTPSessionManager

- (AFHTTPSessionManager *)createSessionManager
{
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    [manager setSecurityPolicy:[self createSecurityPolicy]];
//    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html",@"html/json",@"text/plain", nil];
    [self setHttpHeader:manager];
    
    return manager;
}

#pragma mark 设置请求头

- (void)setHttpHeader:(AFHTTPSessionManager *)manger
{
    // 1. 设备信息
    // 1.1 判断设备，是iphone，ipod还是ipad
    NSString *deviceType = [UIDevice hardwareDescription];
    [manger.requestSerializer setValue:deviceType forHTTPHeaderField:@"Device-Model"];
    [manger.requestSerializer setValue:@"iOS" forHTTPHeaderField:@"User-Agent"];
    
    // 2. 操作系统版本
    NSString *deviceSystemName = [UIDevice currentDevice].systemName;
    NSString *deviceSystemVersion = [UIDevice currentDevice].systemVersion;
    [manger.requestSerializer setValue:[NSString  stringWithFormat:@"%@%@",deviceSystemName,deviceSystemVersion] forHTTPHeaderField:@"Client-OS"];
    
    // 3. 设置app大小版本
    NSString *versionCode = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"versionCode"];
    [manger.requestSerializer setValue:versionCode forHTTPHeaderField:@"versionCode"];
    
    // 4. 设置app大小版本
    NSString *AppVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    [manger.requestSerializer setValue:AppVersion forHTTPHeaderField:@"App-Version"];
}

#pragma mark https证书验证
/*
 AFSecurityPolicy分三种验证模式：
 
 1. AFSSLPinningModeNone
 
 这个模式表示不做SSL pinning，只跟浏览器一样在系统的信任机构列表里验证服务端返回的证书。若证书是信任机构签发的就会通过，若是自己服务器生成的证书，这里是不会通过的。
 
 2. AFSSLPinningModeCertificate
 
 这个模式表示用证书绑定方式验证证书，需要客户端保存有服务端的证书拷贝，这里验证分两步，第一步验证证书的域名/有效期等信息，第二步是对比服务端返回的证书跟客户端返回的是否一致。
 
 这里还没弄明白第一步的验证是怎么进行的，代码上跟去系统信任机构列表里验证一样调用了SecTrustEvaluate，只是这里的列表换成了客户端保存的那些证书列表。若要验证这个，是否应该把服务端证书的颁发机构根证书也放到客户端里？
 
 3. AFSSLPinningModePublicKey
 
 这个模式同样是用证书绑定方式验证，客户端要有服务端的证书拷贝，只是验证时只验证证书里的公钥，不验证证书的有效期等信息。只要公钥是正确的，就能保证通信不会被窃听，因为中间人没有私钥，无法解开通过公钥加密的数据。
 */
- (AFSecurityPolicy *)createSecurityPolicy
{
    AFSecurityPolicy *sec = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
    sec.allowInvalidCertificates = YES;
    return sec;
}



@end
